package jacktgq.mazeSolver.generator;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

/**
 * @Author CandyWall
 * @Date 2021/3/26--0:30
 * @Description 迷宫数据类
 */
public class MazeData {
    public static final char ROAD = ' ';
    public static final char WALL = '#';
    private int entranceX, entranceY;
    private int exitX, exitY;
    private int M, N;
    private char[][] maze;
    public boolean[][] visited;
    public boolean[][] path;
    public boolean[][] result;
    // 是否在迷雾中
    public boolean[][] inDenseFog;

    public MazeData(String filename) {
        if (filename == null) {
            throw new IllegalArgumentException("文件名不能为空！");
        }
        File file = new File(filename);
        if (!file.exists()) {
            throw new IllegalArgumentException("文件不存在！");
        }
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            // 首先读取第一行的行数和列数
            String line = reader.readLine();
            String[] strs = line.split(" ");
            M = Integer.parseInt(strs[0]);
            N = Integer.parseInt(strs[1]);
            maze = new char[M][N];

            // 读取M行数据
            for (int i = 0; i < M; i++) {
                line = reader.readLine();
                // 每行保证有N个字符
                if (line.length() != N) {
                    throw new IllegalArgumentException("第" + i + " 行元素个数不足 " + N + "个！");
                }
                // 每一行的又可以拆分成N个字符
                for (int j = 0; j < N; j++) {
                    maze[i][j] = line.charAt(j);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        visited = new boolean[M][N];
        path = new boolean[M][N];
        result = new boolean[M][N];
        entranceX = 1;
        entranceY = 0;
        exitX = M - 2;
        exitY = N - 1;
    }

    public MazeData(int M, int N) {
        if (M % 2 == 0 || N % 2 == 0) {
            throw new IllegalArgumentException("目前暂不支持生成宽高为偶数规格的迷宫！请将宽高设置为奇数再试！");
        }
        this.M = M;
        this.N = N;

        maze = new char[M][N];
        inDenseFog = new boolean[M][N];
        resetMaze();

        visited = new boolean[M][N];
        path = new boolean[M][N];
        result = new boolean[M][N];
        // System.out.println(this);
    }

    /**
     * 复位迷宫初始状态
     */
    public void resetMaze() {
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                // 如果行数和列数都为奇数，那么就是路
                if (i % 2 == 1 && j % 2 == 1) {
                    maze[i][j] = MazeData.ROAD;
                } else {
                    maze[i][j] = MazeData.WALL;
                }

                inDenseFog[i][j] = true;
            }
        }
        entranceX = 1;
        entranceY = 0;
        exitX = M - 2;
        exitY = N - 1;

        maze[entranceX][entranceY] = MazeData.ROAD;
        maze[exitX][exitY] = MazeData.ROAD;
    }

    /**
     * 复位visited、path、result数组
     */
    public void resetMarkedArray() {
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                visited[i][j] = false;
                path[i][j] = false;
                result[i][j] = false;
            }
        }
    }

    /*public static void main(String[] args) {
        new MazeData(101, 101);
    }*/

    public int getM() {
        return M;
    }

    public int getN() {
        return N;
    }

    public void setMazeDataAt(int x, int y, char value) {
        checkValue(value);
        maze[x][y] = value;
    }

    private void checkValue(int value) {
        if (value != MazeData.ROAD && value != MazeData.WALL) {
            throw new IllegalArgumentException("设置的值不合法：只能为墙或者路的一种！");
        }
    }

    /**
     * 获取迷宫中某个位置的元素
     * @param x
     * @param y
     * @return
     */
    public char getMazeDataAt(int x, int y) {
        return maze[x][y];
    }

    public boolean inArea(int x, int y) {
        return x >= 0 && x < M && y >=0 && y < N;
    }

    public int getEntranceX() {
        return entranceX;
    }

    public int getEntranceY() {
        return entranceY;
    }

    public int getExitX() {
        return exitX;
    }

    public int getExitY() {
        return exitY;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(M + " " + N + "\n");
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                sb.append(maze[i][j]);
            }
            sb.append("\n");
        }

        return sb.toString();
    }

    /**
     * 打开迷雾，这个位置相邻的8个位置上的格子要允许可见
     * @param x
     * @param y
     */
    public void openDenseFog(int x, int y) {
        for (int i = x - 1; i <= x + 1; i++) {
            for (int j = y - 1; j <= y + 1; j++) {
                if (inArea(i, j)) {
                    inDenseFog[i][j] = false;
                }
            }
        }
    }
}
